/*
 * Copyright (C) 2011  John Lawrence thegordo.john at gmail.com
 * Licensed under GPLv3 or later. see http://www.gnu.org/copyleft/gpl.html
 */

package org.jklawrencefam.server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * User: John Lawrence
 * Date: 7/7/11
 * Time: 1:58 AM
 */
public abstract class Server<T extends Processor> {
    private ServerSocket server;
    private static Logger logger = Logger.getLogger(Server.class.getName());
    private Class<T> processor;

    protected Server(Class<T> processor) {
        this.processor = processor;
    }

    public void openPort() {
        try {
            //server = SSLServerSocketFactory.getDefault().createServerSocket(getPort());
            server = new ServerSocket(getPort());
        } catch (IOException e) {
            logger.log(Level.SEVERE, "Could not start with the appropriate port", e);
            e.printStackTrace();
            System.exit(34);
        }
    }

    public void acceptConnections() {
        try {
            Socket socket = server.accept(); // this waits until a connection request is received.
            processIncomingConnection(socket);
        } catch (IOException e) {
            logger.log(Level.SEVERE, "Unable to accept connection", e);
            e.printStackTrace();
        }
    }

    public void close() {
        if (server == null) {
            return;
        }
        try {
            server.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * This should be a short method that starts a new thread to handle a single connection with a client.
     *
     * @param socket - the socket connection with the client.
     */
    protected void processIncomingConnection(Socket socket) {
        try {
            Processor myProcessor = processor.newInstance();
            myProcessor.setSocket(socket);
            myProcessor.run();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    protected abstract int getPort();

    public abstract void configure();
}
